﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

using System.Data;
using System.Data.Sql;

using Common;
using System.Data.SqlClient;

namespace DispatcherLibrary
{
	public delegate void MessageReceivedEventHandler(object sender, string msg);
	public delegate void LobbyEventHandler(object sender, string userName);
	public delegate void InviteEventHandler(object sender, string userName, string invitedUserName);
	public delegate void GameStarted(object sender, GameInfo userName);

	public class Dispatcher : IDispatcher
	{
		static List<string> _users = new List<string>(); //временно

		static Dictionary<string, int> _servers = new Dictionary<string, int>();

		public static event MessageReceivedEventHandler _messageReceivedEvent;
		public static event LobbyEventHandler _lobbyJoin;
		public static event LobbyEventHandler _lobbyLeave;
		public static event InviteEventHandler _invite;
		public static event GameStarted _gameStarted;

		IDispatcherCallback _callback = null;

		MessageReceivedEventHandler _messageReceivedHandler = null;
		LobbyEventHandler _lobbyJoinHandler = null;
		LobbyEventHandler _lobbyLeaveHandler = null;
		InviteEventHandler _inviteHandler = null;
		GameStarted _inviteAcceptedHandler = null;

		string _connectionString = "Data Source=АЛЕКС-ПК\\SQLEXPRESS;Initial Catalog=DBCheckmates;Integrated Security=True";

		/// <summary>
		/// Авторизация пользователя
		/// </summary>
		/// <param name="name">Имя пользователя</param>
		/// <param name="password">Пароль</param>
		/// <returns>Информация об успешности</returns>
		public ReturnInformation Autorization(string name, string password)
		{
			ReturnInformation retInf = new ReturnInformation();
			if (_users.Contains(name))
			{
				retInf.Success = false;
				retInf.ErrorMsg = "Такой пользоватеь уже присутствует";
				return retInf;
			}
			SqlConnection sqlConn = new SqlConnection(_connectionString);
			sqlConn.Open();
			string query = "select * from Users where Username = '" + name + "'";
			SqlCommand sqlCommand = new SqlCommand(query, sqlConn);
			SqlDataReader reader = sqlCommand.ExecuteReader();
			bool hasRows = true;
			if (reader.HasRows)
			{
				if (reader.Read())
				{
					string dbPas = reader.GetValue(1).ToString();
					if (dbPas.Trim() == password)
					{
						retInf.Success = true;
					}
					else
					{
						retInf.Success = false;
						retInf.ErrorMsg = "Неправильное имя пользователя или пароль";
					}
				}
			}
			else 
			{
				hasRows = false;
			}
			reader.Close();
			if (!hasRows)
			{
				string queryInsert = "insert into Users values ('" + name + "','" + password + "')";
				SqlCommand insertCommand = new SqlCommand(queryInsert, sqlConn);
				insertCommand.ExecuteNonQuery();
				retInf.Success = true;
			}
			sqlConn.Close();
			return retInf;
		}

		/// <summary>
		/// Возвращает список текущих игр
		/// </summary>
		/// <returns>Список текущих игр</returns>
		public Games GetCurrentGames()
		{
			Games games = new Games();
			//без бд, могут быть слишком частые обращения + кол-во не такое большое - выгоднее хранить прямо так
			return games;
		}

		public Users GetAllUsers()
		{
			Users users = new Users();
			users.Items = _users;
			return users;
		}

		/// <summary>
		/// Создание игры
		/// </summary>
		/// <param name="gameName">Название игры</param>
		/// <param name="userName">Имя пользователя</param>
		/// <returns>Информация об успешности</returns>
		public void CreateGame(string gameName, string user1Name, string user2Name)
		{
			GameInfo gf1 = new GameInfo();
			GameInfo gf2 = new GameInfo();

			string server = ChooseMin();

			gameName = user1Name + " vs " + user2Name;

			gf1.GameAddress = server;
			gf1.GameId = Guid.NewGuid();
			gf1.GameName = gameName;
			gf1.PlayerType = Player.White;
			gf1.PlayerName = user1Name;

			gf2.GameId = gf1.GameId;
			gf2.GameAddress = server;
			gf2.GameName = gameName;
			gf2.PlayerType = Player.Black;
			gf2.PlayerName = user2Name;
			// логика будет позже

			_gameStarted(this, gf1);
			_gameStarted(this, gf2);
		}

		private string ChooseMin()
		{
			string res = "";
			if (_servers.Count > 0)
			{
				int min = Int32.MaxValue;
				foreach (KeyValuePair<string, int> pair in _servers)
				{
					if (pair.Value < min)
					{
						min = pair.Value;
						res = pair.Key;
					}
				}
			}
			return res;
		}

		public ReturnInformation SpectateGame(string gameName, string userName)
		{
			ReturnInformation retInf = new ReturnInformation();
			return retInf;
		}

		public void Subscribe()
		{
			_callback = OperationContext.Current.GetCallbackChannel<IDispatcherCallback>();
			_messageReceivedHandler = new MessageReceivedEventHandler(MessageReceivedHandler);
			_messageReceivedEvent += _messageReceivedHandler;
			_lobbyJoinHandler = new LobbyEventHandler(LobbyJoinHandler);
			_lobbyJoin += _lobbyJoinHandler;
			_lobbyLeaveHandler = new LobbyEventHandler(LobbyLeaveHandler);
			_lobbyLeave += _lobbyLeaveHandler;
			_inviteHandler = new InviteEventHandler(InviteHandler);
			_invite += _inviteHandler;
			_inviteAcceptedHandler = new GameStarted(GameStart);
			_gameStarted += _inviteAcceptedHandler;
		}

		public void Unsubscribe()
		{
			_messageReceivedEvent -= _messageReceivedHandler;
			_lobbyJoin -= _lobbyJoinHandler;
			_lobbyLeave -= _lobbyLeaveHandler;
			_inviteHandler -= _inviteHandler;
		}

		#region обработчики
		private void MessageReceivedHandler(object sender, string msg)
		{
			_callback.ReceivedMessage(msg);
		}

		private void LobbyJoinHandler(object sender, string userName)
		{
			_callback.UserJoined(userName);
		}

		private void LobbyLeaveHandler(object sender, string userName)
		{
			_callback.UserLeft(userName);
		}

		private void InviteHandler(object sender, string userName, string invitedUserName)
		{
			_callback.Invited(userName, invitedUserName);
		}

		private void GameStart(object sender, GameInfo gameInfo)
		{
			_callback.InviteAccepted(gameInfo);
		}
		#endregion

		public void SendMessage(string msg)
		{
			if (_messageReceivedEvent != null)
				_messageReceivedEvent(this, msg);
		}

		public void JoinLobby(string userName)
		{
			_users.Add(userName);
			if (_lobbyJoin != null)
				_lobbyJoin(this, userName);
		}

		public void LeaveLobby(string userName)
		{
			_users.Remove(userName);
			if (_lobbyLeave != null)
				_lobbyLeave(this, userName);
		}

		public void InviteToGame(string userName, string invitedUserName)
		{
			ReturnInformation res = new ReturnInformation();
			if (_invite != null)
				_invite(this, userName, invitedUserName);
		}

		public void RegisterServer(string serverAddress)
		{
			if (!_servers.ContainsKey(serverAddress))
				_servers.Add(serverAddress, 0);
		}

		public void UnregisterServer(string serverAddress)
		{
			if (_servers.ContainsKey(serverAddress))
				_servers.Remove(serverAddress);
		}
	}
}